package benchmarks.benchmarktests;

import helpers.DataraceException;
import helpers.IAction;
import helpers.RaceConditionException;
import helpers.SafeCounter;
import helpers.UnsafeCounter;
import problems.readerswriters.IReaderWriter;

public class ReadersWritersTest extends BenchmarkTest<IReaderWriter> {
	private int nbReaders;
	private int nbWriters;
	private final SafeCounter safe = new SafeCounter(0);
	private final UnsafeCounter counter = new UnsafeCounter(0);

	public ReadersWritersTest(IReaderWriter solution, int nbReaders, int nbWriters) {
		super(solution);
		this.nbReaders = nbReaders;
		this.nbWriters = nbWriters;
	}

	@Override
	public Thread[] InitializeThreads() {
        Thread[] initializedThreads = new Thread[nbReaders + nbWriters];
        
        //Writers
        for (int i = 0; i < nbWriters; i++)
		{
		    initializedThreads[i] = new Thread() {
		    	public void run() {
		    		solution.write(new IAction() {
		    			public void invoke() {
		    				counter.add(1);
		    			}
		    		});
		    	}
		    };
		}
        
        //Readers
		for (int i = 0; i < nbReaders; i++)
		{
		    initializedThreads[i + nbWriters] = new Thread() {
		    	public void run() {
		    		solution.read(new IAction() {
		    			public void invoke() {
		    				int readNumber = counter.getCount();
		    				int otherNumber = counter.getCount();
		    				if(readNumber != otherNumber) {
		    					safe.add(1);
		    				}
		    			}
		    		});
		    	}
		    };
		}
        return initializedThreads;
	}
	
	@Override
	public void runAdditionalTests() {
		if(safe.getCount() != 0)
			throw new RaceConditionException("Writer in CS at the same time as a Reader");
		if(counter.getCount() != nbWriters) {
			throw new DataraceException("A datarace has occured!");
		}
	}
}
